package com.et.machine.manager.api

import androidx.annotation.IntDef
import com.et.machine.manager.api.Inspector.Companion.CODE_ORDER_REPEAT
import com.et.machine.manager.api.Inspector.Companion.CODE_OVER_MAX_COUNTS
import com.et.machine.manager.api.Inspector.Companion.CODE_SERIAL_ERROR
import com.et.machine.manager.api.Inspector.Companion.CODE_UNKNOWN
import com.et.machine.manager.api.Inspector.Companion.failure
import com.et.machine.manager.api.Inspector.Companion.makeSerialNo
import kotlin.random.Random

class OutGoodsOrderInspector {

    fun inspector(param: AbstractOutParam): Inspector {
        when (param) {
            /*
             * first  >> check repeat order
             * second >> limit max out count
             */
            is OutGoodsParamAndroid -> {
                if (!orderRepeatCheckPassed(param)) return failure(CODE_ORDER_REPEAT)
                if (param.index > MAX_OUT_COUNT) return failure(CODE_OVER_MAX_COUNTS)
            }

            /*
             * first >> check out finish
             */
            is OutGoodsParamTest -> {
                if (param.index == 0) {
                    // TODO yes
                } else {
                    // TODO bye
                }
            }
            is OutGoodsParamVMC -> {
                if (param.index == 0) {
                    // TODO yes
                } else {
                    // TODO bye
                }
            }
            else -> {

            }
        }

        // create serial number
        makeSerialNo().apply {
            if (success) {
                Inspector.pass()
                param.channelInfo.serialNo = this.serial // set serial no
            } else {
                failure(CODE_SERIAL_ERROR)
            }
        }
        return failure(CODE_UNKNOWN)
    }

    companion object {
        @JvmStatic
        fun getInstance() = Holder.ins

        private const val MAX_OUT_COUNT = 10

        /** order repeat */
        private val orderMap = HashMap<String, String>()

        fun orderRepeatCheckPassed(param: OutGoodsParamAndroid): Boolean {
            if (orderMap.containsKey(param.orderInfo.outTradeNo) || orderMap.containsValue(param.orderInfo.outTradeNo)) {
                return false
            }
            orderMap[param.orderInfo.outTradeNo] = param.orderInfo.outTradeNo
            return true
        }

    }

    object Holder {
        val ins = OutGoodsOrderInspector()
    }
}

class Inspector private constructor(
    val passed: Boolean = false,
    private var codePay: String = "",
    private var codeOutGoods: String = ""
) {

    fun getPayCode(): String {
        return codePay
    }

    fun getOutCode(): String {
        return codeOutGoods
    }

    fun changeInspectorFailureStatus(
        @InspectorOutCode code: Int,
    ) {
        when (code) {
            OUT_CODE_SEND_BOARD_TIME_OUT -> {
                codeOutGoods = ""
                codePay = "5"
            }
            OUT_CODE_OUT_GOODS_REFUSE -> {
                codeOutGoods = "98"
                codePay = "6"
            }
            OUT_CODE_OVER_TIME_OUT_GOODS -> {
                codeOutGoods = "99"
                codePay = "6"
            }
        }
    }

    fun changeInspectorSuccessStatus(
        outCode: Int = 0
    ) {
        codePay = "6"
        codeOutGoods = "$outCode"
    }

    companion object {

        /** param preview check */
        @IntDef(
            CODE_ORDER_OVER_TIME,
            CODE_OVER_MAX_COUNTS,
            CODE_SERIAL_ERROR,
            CODE_ORDER_REPEAT,
            CODE_UNKNOWN,
            CODE_PARAM_FAULT
        )
        annotation class InspectorPreCheck

        const val CODE_ORDER_OVER_TIME = 1
        const val CODE_OVER_MAX_COUNTS = 2
        const val CODE_SERIAL_ERROR = 3
        const val CODE_ORDER_REPEAT = 4
        const val CODE_PARAM_FAULT = 5
        const val CODE_UNKNOWN = 404

        fun failure(@InspectorPreCheck code: Int): Inspector {
            when (code) {
                CODE_ORDER_OVER_TIME -> {
                    return Inspector(false, "6", "97")
                }
                CODE_OVER_MAX_COUNTS -> {
                    return Inspector(false, "5", "96")
                }
                CODE_SERIAL_ERROR -> {
                    return Inspector(false, "5", "95")

                }
                CODE_PARAM_FAULT -> {
                    return Inspector(false, "5", "94")
                }
                CODE_UNKNOWN -> {

                }
                else -> {

                }
            }
            return Inspector(false, "", "")
        }

        fun pass() = Inspector(true, "4", "")


//        String O_NL = ""; 5,"" send time out
//        String O_93 = "93"; // 订单SMILE or FACE http failed 5,93
//        String O_94 = "94"; // 订单参数异常 5,94
//        String O_95 = "95"; // 订单流水失败 5,95
//        String O_96 = "96"; // 订单超数量 5,96
//        String O_97 = "97"; // 订单超时 6 97
//        String O_98 = "98"; // 主控拒绝出货 6,98
//        String O_99 = "99"; // 主控许久未返回出货结果 6,99

        /**  out result after */
        @IntDef(OUT_CODE_SEND_BOARD_TIME_OUT, OUT_CODE_OUT_GOODS_REFUSE, OUT_CODE_OVER_TIME_OUT_GOODS)
        annotation class InspectorOutCode

        const val OUT_CODE_SEND_BOARD_TIME_OUT = 11
        const val OUT_CODE_OUT_GOODS_REFUSE = 12
        const val OUT_CODE_OVER_TIME_OUT_GOODS = 13

        /** make serial number */
        private const val MAX_SERIAL_TIMES = 10

        private val serialMap = HashMap<Int, Int>()

        data class Serial(val success: Boolean = false, val serial: Int)

        fun makeSerialNo(): Serial {
            var times = MAX_SERIAL_TIMES
            do {
                Random.nextInt(999999).apply {
                    if (!serialMap.containsKey(this) && !serialMap.containsValue(this)) {
                        serialMap[this] = this
                        return Serial(true, this)
                    }
                }
            } while (times-- > 0)
            return Serial(false, -1)
        }
    }
}